﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlTypes;

namespace dasBlog.Storage.SqlServer
{
    public class LogDataStorageProvider : SqlStorageProviderBase<LogEntry, LogData, dasBlogStorageSqlDataContext>
    {
        public override IEnumerable<LogEntry> Select(Moniker moniker, MonikerMatch contextMatch, QueryDescription query)
        {
            if (query == null)
            {
                if (contextMatch == MonikerMatch.Exact)
                {
                    return from LogData e in ReadContext.LogDatas
                           where e.ContextKey == moniker.ItemPath
                           orderby e.RequestTime descending
                           select FromSqlType(e);
                }
                else
                {
                    return from LogData e in ReadContext.LogDatas
                           where moniker.ToString() == e.ContextKey.Substring(0, moniker.ToString().Length)
                           orderby e.RequestTime descending
                           select FromSqlType(e);
                }
            }
            else
            {
                var args = new Dictionary<string, string>();
                foreach (QueryArgument arg in query.Arguments)
                {
                    args.Add(arg.Name, arg.Value);
                }

                if (query.QueryName == DateRangeAndTagQueryDescription.Name)
                {
                    DateTime @from =
                        args[DateRangeAndTagQueryDescription.FromArgument] != null ?
                        DateTime.Parse(args[DateRangeQueryDescription.FromArgument]).ToSqlRange() :
                        DateTimeTools.SqlMin;
                    DateTime @to =
                        args[DateRangeAndTagQueryDescription.ToArgument] != null ?
                        DateTime.Parse(args[DateRangeQueryDescription.ToArgument]).ToSqlRange() :
                        DateTimeTools.SqlMax;

                    if (contextMatch == MonikerMatch.Exact)
                    {
                        return from LogData e in ReadContext.LogDatas
                               where
                                  e.ContextKey == moniker.ItemPath &&
                                  e.TrackingType == args[DateRangeAndTagQueryDescription.TagArgument] &&
                                  e.RequestTime < @to &&
                                  e.RequestTime > @from
                               orderby e.RequestTime descending
                               select FromSqlType(e);
                    }
                    else
                    {
                        return from LogData e in ReadContext.LogDatas
                               where moniker.ToString() == e.ContextKey.Substring(0, moniker.ToString().Length) &&
                                  e.TrackingType == args[DateRangeAndTagQueryDescription.TagArgument] &&
                                  e.RequestTime < @to &&
                                  e.RequestTime > @from
                               orderby e.RequestTime descending
                               select FromSqlType(e);
                    }
                }
                else if (query.QueryName == "ReferrerUrl")
                {
                    if (contextMatch == MonikerMatch.Exact)
                    {
                        return from LogData e in ReadContext.LogDatas
                               where
                                  e.ContextKey == moniker.ItemPath &&
                                  e.ReferrerUrl == args["ReferrerUrl"] 
                               orderby e.RequestTime descending
                               select FromSqlType(e);
                    }
                    else
                    {
                        return from LogData e in ReadContext.LogDatas
                               where moniker.ToString() == e.ContextKey.Substring(0, moniker.ToString().Length) &&
                                  e.ReferrerUrl == args["ReferrerUrl"] 
                               orderby e.RequestTime descending
                               select FromSqlType(e);
                    }
                }
                else
                {
                    return null;
                }
            }
        }

        public override IEnumerable<PropertyAggregate> Aggregate(Moniker contextId, MonikerMatch contextMatch, string propertyName)
        {
            throw new NotImplementedException();
        }

        protected override void UpdateSqlTypeFromStgType(LogEntry item, LogData existingEntry)
        {
            existingEntry.Country = item.Country;
            existingEntry.Location = item.Location;
            existingEntry.RequestTime = item.RequestTime;
            existingEntry.TrackingType = item.TrackingType;
            existingEntry.ReferrerUrl = item.ReferrerUrl;
            existingEntry.ReferrerName = item.ReferrerName;
            existingEntry.ReferrerTitle = item.ReferrerTitle;
            existingEntry.UrlRequested = item.UrlRequested;
            existingEntry.UserAgent = item.UserAgent;
            existingEntry.UserDomain = item.UserDomain;
            existingEntry.UserIP = item.UserDomain;
            existingEntry.TargetId = item.TargetId;
            existingEntry.TargetTitle = item.TargetTitle;
        }

        protected override LogData FromStgType(Moniker contextUri, LogEntry item)
        {
            if (item.Id != null)
            {
                Moniker id = MonikerFromStgType(item);
                return new LogData
                {
                    ContextKey = id.ItemPath,
                    Id = id.ItemId,
                    Country = item.Country,
                    Location = item.Location,
                    RequestTime = item.RequestTime,
                    TrackingType = item.TrackingType,
                    ReferrerUrl = item.ReferrerUrl,
                    ReferrerName = item.ReferrerName,
                    ReferrerTitle = item.ReferrerTitle,
                    UrlRequested = item.UrlRequested,
                    UserAgent = item.UserAgent,
                    UserDomain = item.UserDomain,
                    UserIP = item.UserDomain,
                    TargetId = item.TargetId,
                    TargetTitle = item.TargetTitle
                };
            }
            else
            {
                return new LogData
                {
                    ContextKey = contextUri.ItemPath,
                    Id = Guid.NewGuid().ToString(),
                    Country = item.Country,
                    Location = item.Location,
                    RequestTime = item.RequestTime,
                    TrackingType = item.TrackingType,
                    ReferrerUrl = item.ReferrerUrl,
                    ReferrerName = item.ReferrerName,
                    ReferrerTitle = item.ReferrerTitle,
                    UrlRequested = item.UrlRequested,
                    UserAgent = item.UserAgent,
                    UserDomain = item.UserDomain,
                    UserIP = item.UserDomain,
                    TargetId = item.TargetId,
                    TargetTitle = item.TargetTitle
                };
            }
        }

        protected override LogEntry FromSqlType(LogData item)
        {
            Moniker id = MonikerFromSqlType(item);
            return new dasBlog.Storage.LogEntry
            {
                Id = id,
                Country = item.Country,
                Location = item.Location,
                RequestTime = item.RequestTime.GetValueOrDefault(DateTime.Now),
                TrackingType = item.TrackingType,
                ReferrerUrl = item.ReferrerUrl,
                ReferrerName = item.ReferrerName,
                ReferrerTitle = item.ReferrerTitle,
                UrlRequested = item.UrlRequested,
                UserAgent = item.UserAgent,
                UserDomain = item.UserDomain,
                UserIP = item.UserDomain,
                TargetId = item.TargetId,
                TargetTitle = item.TargetTitle
            };
        }

        protected override Moniker MonikerFromSqlType(LogData newEntry)
        {
            return new Moniker(new Moniker(newEntry.ContextKey), newEntry.Id.ToString());
        }

        protected override Moniker MonikerFromStgType(LogEntry item)
        {
            return item.Id;
        }

        protected override Func<LogData, bool> MatchSingle(Moniker contextUri)
        {
            return (e) => e.ContextKey == contextUri.ItemPath &&
                          e.Id == contextUri.ItemId;
        }
    }
}
